package com.mdc.log.aspect;

import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mdc.log.annotation.SysLog;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 操作日志打印日志，暂时不入库
 *
 * @author pcheng reviewcode@163.com
 * @date 17:01 2021/8/1
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class SysLogAspect {
    private final ApplicationEventPublisher publisher;

    @SneakyThrows
    @Around("@annotation(sysLog)")
    public Object around(ProceedingJoinPoint point, SysLog sysLog) {
        Long startTime = System.currentTimeMillis();
        Object obj = null;
        try {
            obj = point.proceed();
        } finally {
            Long endTime = System.currentTimeMillis();
            long diffTime = endTime - startTime;
            printAccessLog(point, obj, diffTime, sysLog);
        }
        return obj;
    }

    /**
     * 打印出入参数日志
     *
     * @param point 切点
     * @param obj 返回结果
     * @param diffTime 时间话费
     * @param sysLog 日志注解
     */
    private void printAccessLog(ProceedingJoinPoint point, Object obj, long diffTime, SysLog sysLog) {
        try {
            boolean response = sysLog.response();
            if (!response) {
                obj = "response is false";
            }
            List<Object> filteredArgs = Arrays.stream(point.getArgs())
                    .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)))
                    .collect(Collectors.toList());
            ObjectMapper mapper = new ObjectMapper();
            String reqParam = mapper.writeValueAsString(filteredArgs);

            String strClassName = point.getTarget().getClass().getName();
            String strMethodName = point.getSignature().getName();
            String value = sysLog.value();
            log.info("{}【类名方法:{}.{}】\n【入参:{}】\n【出参:{}】\n【耗时：{}ms】\n",
                    value,
                    strClassName,
                    strMethodName,
                    reqParam,
                    JSONUtil.toJsonStr(obj),
                    diffTime
            );
        } catch (Exception e) {
            log.error("printAccessLog打印日志错误：\n", e);
        }
    }
}
